YAS: Y86-64 assembler (.ys → .yo)
YIS: Y86-64 simulator (run .yo programs)
CC:ZF SF OF
注意 mrmovq 顺序(原因:valA 与 valC 不能同时进入 execute 阶段)
Y86-64只有addq,subq,andq,xorq
1a | b = (a & ~b) ^ b此处 IOPL 需改为 IOPQ
条件不一定互斥,按次序比对,选择第一个值为 1 的式子
xxxxxxxxxx61word out = [2 !s0 && !s1 : A # 003 !s1 : B # 014 !s0 : C # 105 1 : D # 116 ]判等
MUX 多路复用器
寄存器由锁存器或触发器构成
读是组合逻辑,写是时序逻辑
SEQ 分为 6 个阶段
取址:Fetch
译码:Decode
执行:Execute
访存:Memory
写回:Write back
更新 PC:PC Update
总结
W:只能写入valE,valM(rrmovq,irmovq,cmovXX需要+0做ALU计算)
分则
此处与W_valM, W_valE的判断顺序对应
IOPL改为IOPQ
RESP改为RRSP
结构
HCL
icode
ifun
instr_vaild
need_rgids
need_valC
结构
HCL
srcA
srcB
dstE
dstM
结构
HCL
alufun
aluA
aluB
set_cc
结构
HCL
mem_read
mem_write
mem_addr
mem_data
Stat
结构
HCL
new_pc
电路重定时:改变状态表示而不改变逻辑
目的:平衡一个流水线各个阶段之间的延迟
在 SEQ+ 的实现里,PC update 的时期从周期的最后被提到了最前,更加接近流水线的形态
在 Y86-64 的实现中:
正常指令指令默认预测 PC 为下一条指令的地址;
call 指令和 jxx 指令默认预测 PC 为跳转后地址;
ret 指令不进行任何预测,直到其对应的写回完成
分别插入了5个流水线寄存器用来保存后续阶段所需的信号,编号为F、D、E、M和W
Fetch: Select current PC;Read instruction;Compute incremented PC
Decode:Read program registers
Execute:Operate ALU
Memory:Read or write data memory
Write Back:Update register file
寄存器顺序:F—f—D—d—E—e—M—m—W
各个寄存器作用:
F:保存程序计数器的预测值
D:保存取指信息
E:保存关于最新译码的指令 && 从寄存器文件中读出的值
M:保存最新执行指令的结果 && 关于处理条件转移的分支条件和目标信息
W:位于访存和反馈路径之间
在SEQ+中,在译码阶段通过逻辑电路计算得到
dstE和dstM,会直接将其连接到寄存器文件的写端口的地址输入,当计算出valE和valM时直接写回到对应寄存器中。但是dstE和dstM是在译码阶段计算出来的,而valE是在执行阶段计算得到,valM是在访存阶段获得的,在流水线系统PIPE-中各个阶段是相互独立的,当某条指令运行到写回阶段时,得到了valE和valM,但是当前的dstE和dstM是处于译码阶段的指令计算出来的,会出现错误,所以需要将dstE和dstM一直保存到后续的流水线寄存器中。
通用规则:我们要保存处于一个流水线阶段中的指令的所有信息
只有
call指令需要将valP保存到内存中,即我们为了call指令需要将取指阶段得到的valP一直保存到后续的流水线寄存器中,直到访存阶段将其保存到内存中。但是我们发现call指令只使用valB保存%rsp的值,并不会使用valA,所以我们可以通过PIPE-中的selectA模块将valP保存到valA,由此就不需要保存valP了。同理条件跳转指令,当不选择跳转分支时,后面也需要valP,也可以将其保存到valA中,由此也不需要保存valP了。
通用规则:通过合并信号来减少寄存器状态和线路的数量
S_Field:Value of Field held in stage S pipeline register
s_Field:Value of Field computed in stage S
PC Select 从三个程序计数器源中进行选择:
F_predPC:一般情况下一条指令
M_valA:预测分支错误时,从跳转到valP指向地址
W_valM:ret时,读出返回地址
条件分支:我们可以通过分支预测技术来预测分支方向,并根据预测开始取值。常见的技术包括:
静态分支预测
总是选择(always taken,AT):预测PC值为valC,成功率大约为60%。
从不选择(never taken,NT):预测PC值为valP,成功率大约为40%。
反向选择、正向不选择(backward taken, forward not-taken,BTFNT):考虑条件分支通常用于循环操作, 成功率大约为65%。
动态分支预测
分支预测缓存:包含一个或多个比特,以表明一个分支是否发生了跳转
锦标赛分支预测器:对于每个分支具有多种预测,并对预测进行选择
ret指令:常见的技术包括
暂停处理新指令,直到ret指令通过写回阶段知道下一条指令的地址
在取指单元中放入一个硬件栈,保存过程调用指令产生的返回地址
stall能将指令阻塞在某个阶段
bubble能使得流水线继续运行,但是不会改变当前阶段的寄存器、内存、条件码或程序状态
计算的多时钟周期
采用独立于主流水线的特殊硬件功能单元来处理较为复杂的操作
(一个功能单元执行整数乘法和除法,一个功能单元执行浮点操作)
访存的多时钟周期
翻译后备缓冲器(TLB)+高速缓存(Cache):实现一个时钟周期内读指令并读或写数据
缺页(page fault)异常信号:指令暂停+磁盘到主存传送+指令重新执行
插入一段自动产生的nop指令
该方法指令要停顿最少一个最多三个时钟周期,严重降低整体的吞吐量
若不插入:
版本1:
版本2:
用转发来避免数据冒险
在处理器中,valA和valB一共有5个转发源:
e_valE:在执行阶段,ALU中计算得到的结果valE,通过E_dstE与d_srcA和d_src_B进行比较决定是否转发。
M_valE:将ALU计算的结果valE保存到流水线寄存器M中,通过M_dstE与d_srcA和d_src_B进行比较决定是否转发。
m_valM:在访存阶段,从内存中读取的值valM,通过M_dstM与d_srcA和d_src_B进行比较决定是否转发。
W_valM:将内存中的值valM保存到流水线寄存器W中,通过W_dstM与d_srcA和d_src_B进行比较决定是否转发。
W_valE :将ALU计算的结果valE保存到流水线寄存器W中,通过W_dstE与d_srcA和d_src_B进行比较决定是否转发。
不能单独通过转发实现(M,D——中间跨阶段)
加载互锁(Load Interlock)方法
核心思想:通过暂停+转发组合实现
形式:(Install)+bubble ——最后一定要插入bubble避免后续在流水线中继续进行
删除后续操作——插入3个bubble
版本1
版本2
处理预测错误的分支
删除后续操作——插入2个bubble
有限性组合:Combination A + B
Conbination A:ret位于不选择分支 ——简单叠加
Conbination B:加载/使用+ret ——取”stall”
加载互锁核心思想:通过暂停+转发组合实现
合理性:Install后,下一条指令无法进入寄存器,当前指令因为bubble并未成功下传
有效性:Install后,当前指令ret依然存在于流水线中,加载/使用语句后可进一步执行
内部异常:Stat:{HLT, ADR, INS}
HLT:执行halt指令
ADR:从非法内存地址读或向非法内存地址写
INS:非法指令
外部异常
系统重启
I/O设备请求
硬件故障
要求:异常指令之前的所有指令已经完成,后续的指令都不能修改条件码寄存器和内存。
问题:
当同时多条指令引起异常时,处理器应该向操作系统报告哪个异常?
基本原则:由流水线中最深的指令引起的异常,表示该指令越早执行,优先级最高。
在分支预测中,当预测分支中出现了异常,而后由于预测错误而取消该指令时,需要取消异常。
如何处理不同阶段更新系统状态不同部分的问题?
异常发生时,记录指令状态,继续取指、译码、执行
异常到达访存阶段:
执行阶段,禁止设置条件码(set_cc
访存阶段,插入气泡,禁止写入内存
写回阶段,暂停写回,即暂停流水线
控制权移交操作系统
统例外程序计数器(SEPC)
系统例外原因寄存器(SCAUSE)
PC的更新
非精确中断(PIPE)
精确中断(RISC-V)
结构
HCL
f_predPC(总是跳转版)
f_pc
PC Select 从三个程序计数器源中进行选择:
f_predPC:一般情况下一条指令
M_valA:预测分支错误时,跳转到valP指向地址
由于在 Execute 阶段之后,会用到 valP 的指令 call/jxx 不会使用 valA,因此在 Decode 阶段中,valA、valP 二者被合并
W_valM:ret时,读出返回地址
instr_vaild
need_regids
need_valC
f_icode
f_ifun
f_stat
结构
HCL
合并信号:Sel+FwdA
转发逻辑:
e_valE、m_valM、M_valE、W_valM和W_valE,从左到右依次降低的优先级
d_valA(先M后E)
d_valB
d_srcA
d_srcB
d_dstE(valE->R[rB])
d_dstM(valM->R[rA])
结构
Set CC 使用了 W_stat 和 m_stat 作为控制条件,这是为了让异常能够正确处理,在异常发生后禁止更新条件码
注意转发给 Decode 阶段的是 e_dstE 而不是 E_dstE,因为条件传送在条件不满足时应该把 dstE 设置为 RNONE,这是在 Execute 阶段中做的更新
HCL
aluA
aluB
alufun
e_valA
e_dstE(考虑cmov)
set_cc
结构
注意 Address 与 Data 的区别消失,因为其工作合并 valA 与 valP 在 Sel + Fwd A 中被执行
HCL
mem_read
mem_write
mem_addr
mem_data? 恒等于valA(include orignial valA,valP)
m_stat
Stat(考虑bubble影响)
xxxxxxxxxx51wordsig SBUB ’STAT_BUB’ # Bubble in stage2wordsig SAOK ’STAT_AOK’ # Normal execution3wordsig SADR ’STAT_ADR’ # Invalid memory address4wordsig SINS ’STAT_INS’ # Invalid instruction5wordsig SHLT ’STAT_HLT’ # Halt instruction encountered结构
HCL
在异常发生后,需要完成三件事:
禁止任何条件码的更新
对下一周期 M 阶段插入 bubble
将异常指令在 W 阶段进行 stall